/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package enterprise.servlet_stateless_ejb;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Random;
import java.util.Scanner;
import java.util.Vector;

/**
 *
 * @author jzou
 */
public class EnglishNameGenerator {

    static Vector names = new Vector(200);

    private static boolean hasFriends(int i) {
        return getFriends(getNode(i)) != null;
    }

    public Vector readEnglishNames(String fileName) {
        InputStream is = getClass().getResourceAsStream(fileName);
        Scanner s = null;
        try {
            s = new Scanner(is);

            while (s.hasNext()) {
                names.add(s.next());
            }
        } finally {
            if (s != null) {
                s.close();
            }
        }

        return names;
    }

    public static void main(String[] args) {
        Object[] buznet = generateNames();
//        dumpTree();
        initialize();
        friendsStatistic(buznet);
//        dictionaryDemo();
    }

    public static void printNames() {
        Vector<String> names = new Vector(200);
        EnglishNameGenerator eng = new EnglishNameGenerator();

        names = eng.readEnglishNames("englishNames.txt");
        for (String i : names) {
            System.out.println(i);
        }
    }

    // BUZNET_CAPACITY = 960000; ~= 1M items in Vector will spent 64M Java heap space.
    // 1 items ~= 64 bytes
//    public static void generateNames_Vector_obsolete() {
//        final int BUZNET_CAPACITY = 10000;      // 1 people have 48 friends ~= half Java heap space
//        Vector names = new Vector(200);
//        EnglishNameGenerator eng = new EnglishNameGenerator();
//        Vector nodes = new Vector(BUZNET_CAPACITY);
//
//        names = eng.readEnglishNames("englishNames.txt");
//        for (int i = 0; i < BUZNET_CAPACITY; i++) {
//            StringBuffer sb = new StringBuffer();
//            int randomIndex;
//            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
//            sb.append(names.get(randomIndex) + " ");
//            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
//            sb.append(names.get(randomIndex));
//            Vector node = new Vector();
//            nodes.add(node);
//            nodes.add(sb.toString());
//        }
//    }
    public static void dictionaryDemo() {
        Hashtable<String, Hashtable> a = new Hashtable();
        Hashtable<String, Hashtable> b = new Hashtable();
        Hashtable<String, Hashtable> c = new Hashtable();

        b.put("leaf", c);
        a.put("root", b);

        System.out.println(a);
    }

//    public static void generateNames_failed_by_hashtable() {
//        final int BUZNET_CAPACITY = 100;
//        Hashtable<String, Hashtable> terminator = new Hashtable();
//        Vector names = new Vector();
//        EnglishNameGenerator eng = new EnglishNameGenerator();
//        Hashtable<String, Hashtable> nodes = new Hashtable(BUZNET_CAPACITY);
//
//        names = eng.readEnglishNames("englishNames.txt");
//        for (int i = 0; i < BUZNET_CAPACITY; i++) {
//            StringBuffer sb = new StringBuffer();
//            int randomIndex;
//            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
//            sb.append(names.get(randomIndex) + " ");
//            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
//            sb.append(names.get(randomIndex));
//            nodes.put(sb.toString(), terminator);
//        }
//
//        Vector<Hashtable> indexNodes = new Vector(nodes.entrySet());
//        for (String key : nodes.keySet()) {
//            // if 1 people node have 25 friends then
//            Hashtable<String, Hashtable> node;
//            node = nodes.get(key);
//            for (int j = 0; j < 25; j++) {
////                int selectedFriendNum;
////                selectedFriendNum = (int) Math.round(Math.random() * (nodes.size() - 1));
////                Hashtable selectFriend = indexNodes.elementAt(selectedFriendNum);
//                Hashtable selectFriend = new Hashtable();
//                selectFriend.put("friend " + j, "");
//                node.put("friend" + j, selectFriend);
//            }
//        }
//        System.out.println(nodes);
//    }
    enum Columns {

        NAME, FRIENDS
    }
    final static int BUZNET_CAPACITY = 10000;      // 1 people have 48 friends ~= half Java heap space
    private static Object[] nodes = new Object[BUZNET_CAPACITY];
    private static boolean[] visited = new boolean[BUZNET_CAPACITY];


    {
        for (int i = 0; i < BUZNET_CAPACITY; i++) {
            visited[i] = false;
        }
    }

    public static String getRandomName() {
        StringBuffer sb = new StringBuffer();
        int randomIndex;
        randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
        sb.append(names.get(randomIndex) + " ");
        randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
        sb.append(names.get(randomIndex));
        return sb.toString();
    }

    public static Object[] generateNames() {

        Vector names = new Vector(200);
        EnglishNameGenerator eng = new EnglishNameGenerator();


        Random r = new Random();
        names = eng.readEnglishNames("englishNames.txt");
        for (int i = 0; i < BUZNET_CAPACITY; i++) {
            StringBuffer sb = new StringBuffer();
            int randomIndex;
            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
            sb.append(names.get(randomIndex) + " ");
            randomIndex = (int) Math.round(Math.random() * (names.size() - 1));
            sb.append(names.get(randomIndex));
            Object[] node = {
                sb.toString(), // Object[0] = name
                null // Object[1] = friends
            };
            nodes[i] = node;
        }

        // generate friends
        for (int i = 0; i < BUZNET_CAPACITY; i++) {
            // node[0] -- people name
            // node[1] -- friends
            int friendNumber = (int) Math.round(r.nextGaussian() * 25 - 15);
            if (friendNumber > 0) {
                int[] friends = new int[friendNumber];
                for (int j = 0; j < friendNumber; j++) {
                    friends[j] = (int) Math.round(Math.random() * (nodes.length - 1));
                }
                Object[] node = getNode(i);
                setFriends(node, friends);
            }
        }

        // generate products
        // Assuming that there are 5% members have renting apartment business
        for (int j = 0; j < BUZNET_CAPACITY * 0.05; j++) {
            int i = (int) Math.round(Math.random() * (nodes.length - 1));
            String rentingApartment = "出租：两居室，85平米，南北向";
            Object[] node = {
                getNode(i)[0],
                getNode(i)[1],
                rentingApartment
            };
            nodes[i] = node;
        }

        return nodes;
    }

    private static void initialize() {
        friendCount = 0;
        for (int i = 0; i < visited.length; i++) {
            visited[i] = false;
        }
    }

    public static void dumpTree() {
        System.out.println("Begin dumpTree");
        for (int i = 0; i < nodes.length; i++) {
            if (hasFriends(i)) {
                friendCount = 0;
                _dumpTree(i, 0, "");
            } else {
                System.out.println(i + "have no friends");
            }
        }
    }
    private static int friendCount = 0;

    private static void _dumpTree(int nodeID, int level, String path) {
        // dealing with the member of the network
        Object[] node = getNode(nodeID);
        String name = getNodeName(node);
        int[] friends = getFriends(node);
        visited[nodeID] = true;
        friendCount++;
        output(level, name);

        // searching friends
        if (friends == null) {
        } else {
            for (int i = 0; i < friends.length; i++) {
                int friend = friends[i];
                if (visited[friend]) {
//                    System.out.println("DEBUG : Visited " + nodeID);
//                    System.out.print(".");
                } else {
                    output(level, name);
                    _dumpTree(friend, level + 1, path + "Friends[" + i + "]");
                }
            }
        }
    }

    public static void friendsStatistic(Object[] nodes) {
        System.out.println("Begin statistic friends for all members");
        for (int i = 0; i < nodes.length; i++) {
            if (hasFriends(i) && !visited[i]) {
//                initialize();
                friendCount = 0;
//                System.out.println(i + " have " + getFriends(getNode(i)).length + "direct friends");
                _friendsStatistic(i, 0, "");
//                System.out.println(i + " have ( " + getFriends(getNode(i)).length + " " + friendCount + " ) friends");
//                System.out.println(i + "\t" + getFriends(getNode(i)).length + "\t" + friendCount);
            } else {
//                System.out.println(i + " has no friends");
//                System.out.println(i + "\t0\t0");
            }
        }
    }

    private static void _friendsStatistic(int nodeID, int level, String path) {
        Object[] node = getNode(nodeID);
        String name = getNodeName(node);
        int[] friends = getFriends(node);
        visited[nodeID] = true;
        friendCount++;
//        output(level, path + " : " + name);
//        output(level, name);
//        if (children == null || level > 3) {
        if (friends == null) {
        } else {
            for (int i = 0; i < friends.length; i++) {
                int friend = friends[i];
                if (visited[friend]) {
//                    System.out.println("DEBUG : Visited " + nodeID);
//                    System.out.print(".");
                } else {
//                    output(level, name);
//                    System.out.println(i + " " + nodeID + " " + friendCount);
                    _friendsStatistic(friend, level + 1, path + "Friends[" + i + "]");
                }
            }
            if (level == 0) {
                System.out.println(nodeID + "\t" + name + "\t" + friends.length + "\t" + friendCount);
            }
        }
    }

    private static Object[] getNode(int i) {
        return (Object[]) nodes[i];
    }

    private static String getNodeName(Object[] node) {
        return (String) node[0];
    }

//    private static Object[] getFriends(Object[] node) {
//        return (Object[]) node[1];
//    }
    private static int[] getFriends(Object[] node) {
        return (int[]) node[1];
    }

    private static void setFriends(Object[] node, int[] friends) {
        node[1] = friends;
    }

    public static void output(int level, String outStr) {
        System.out.print(repeat("*", level / 50));
        System.out.println(outStr);
    }

    public static String repeat(String seed, int num) {
        String result = "";
        for (int i = 0; i < num; i++) {
            result += seed;
        }
        return result;
    }
}
